package com.wbihua.common.metrics.metric.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.SafeConcurrentHashMap;
import com.wbihua.common.metrics.manager.MetricManager;
import com.wbihua.common.metrics.metric.EventMeterTimer;
import com.wbihua.common.metrics.type.EventTimerType;
import io.micrometer.core.instrument.Timer;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class EventTimer implements EventMeterTimer {
    private static final SafeConcurrentHashMap<List<String>, Timer> POOL = new SafeConcurrentHashMap<>();
    private Timer timer;

    private final EventTimerType counterType;
    private MetricManager metricManager;

    public EventTimer(EventTimerType counterType) {
        this.counterType = counterType;
    }

    public EventTimer(EventTimerType counterType, MetricManager metricManager) {
        this(counterType);
        this.metricManager = metricManager;
    }
    @Override
    public void registry(MetricManager metricManager) {
        //this.timer =metricManager.getMetricRegistry().timer(getCounterType().getName(), metricManager.getTags());
    }

    @Override
    public <T> T getMeter() {
        return (T)this.timer;
    }

    @Override
    public <T> T getMeter(String... tagValues) {
        return (T)POOL.get(tagValues);
    }

    @Override
    public EventTimerType getCounterType() {
        return this.counterType;
    }

    @Override
    public void record(long amount, TimeUnit unit) {
        this.timer.record(amount, unit);
    }

    @Override
    public void record(long amount, TimeUnit unit, String... tagValues) {
        this.getTimer(tagValues).record(amount, unit);
    }

    @Override
    public void record(Runnable f) {
        this.timer.record(f);
    }

    @Override
    public void record(Runnable f, String... tagValues) {
        this.getTimer(tagValues).record(f);
    }

    @Override
    public void startTimer(Consumer<Timer.Sample> saveTimer, String... tagValues) {
        Timer.Sample sample = Timer.start(metricManager.getMetricRegistry());
        saveTimer.accept(sample);
    }

    @Override
    public void stopTimer(Supplier<Object> timerSupplier, String... tagValues) {
        Timer.Sample sample = (Timer.Sample)timerSupplier.get();
        sample.stop(getTimer(tagValues));
    }

    private Timer getTimer(String[] tagValues) {
        if (tagValues.length != counterType.getTags().length) {
            throw new IllegalArgumentException("Incorrect number of labels.");
        }
        for (String value: tagValues) {
            if (value == null) {
                throw new IllegalArgumentException("Label cannot be null.");
            }
        }
        return POOL.computeIfAbsent(ListUtil.toList(tagValues), values -> {
            Timer.Builder builder = Timer.builder(this.counterType.getName())
                    .tags(metricManager.getTags());
            String[] tags = counterType.getTags();
            for (int i = 0; i < values.size(); i++) {
                builder.tag(tags[i], values.get(i));
            }
            return builder.publishPercentiles(this.counterType.getPercentiles())
                    .publishPercentileHistogram(true)
                    .description(counterType.getDescription())
                    .register(metricManager.getMetricRegistry());
        });
    }
}
